package com.wei.czz.framework.index.service.impl;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.blog.BlogDto;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.blog.BlogEnum;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.RandomNumUtils;
import com.wei.czz.common.utils.TimeUtils;
import com.wei.czz.framework.common.handler.redis.RedisStringHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.common.vo.blog.SortVo;
import com.wei.czz.framework.index.service.SortService;
import com.wei.czz.framework.blog.service.BlogIssueService;
import lombok.AllArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-05-25 23:22:00
 * className: SortServiceImpl 浏览器页面-排序页面-服务接口实现类
 * version: 1.0
 * description:
 */
@Service("sortService")
@AllArgsConstructor
public class SortServiceImpl implements SortService {

    private final BlogIssueService blogIssueService;

    private final RedisStringHandler redisStringHandler;

    private final RedisHandler redisHandler;

    private final RedissonClient redissonClient;

    @Override
    public PageDto<BlogDto> synthesizeBlogList(SortVo sortVo, BlogEnum blogEnum) {
        // 获取
        String sortListKey = sortVo.getSortListKey();
        // 获取Redis分布式锁对象
        RLock lock = redissonClient.getLock(RedisConstant.LOCK + sortListKey);
        // 查询Redis，获取综合排序博客列表缓存
        PageDto<BlogDto> pageDto = redisStringHandler.get(sortListKey);
        if (pageDto != null) {
            // 尝试更新缓存键的过期时间
            redisHandler.tryUpdateKeyExpire(sortListKey, 150, RandomNumUtils.random5Minutes(10));
            return pageDto;
        }
        // 加锁30秒
        lock.lock(30, TimeUnit.SECONDS);

        try {
            // 重复查询Redis，获取综合排序博客列表缓存
            pageDto = redisStringHandler.get(sortListKey);
            if (pageDto != null) {
                return pageDto;
            }

            Date date = new Date();
            // mp分页对象
            Page<BlogDto> page = new Page<>(sortVo.getPage(), sortVo.getLimit());

            switch (blogEnum) {
                // 今日发布的博客
                case DAY_BLOG:
                    // 按照发布时间降序排序
                    page.addOrder(OrderItem.desc("issue_time"));
                    // 获取系统时间所在日的开始时间
                    Date startToDay = TimeUtils.startToDay();
                    // 分页查询参数时间范围内的系统已发布博客列表（时间范围：左闭右闭区间）
                    blogIssueService.getSynthesizeBlogList(page, sortVo, startToDay, date);
                    break;
                // 这个月发布的博客
                case MONTH_BLOG:
                    // 按照发布时间降序排序
                    page.addOrder(OrderItem.desc("issue_time"));
                    // 获取系统时间所在月的开始时间（一日零点零分零秒）
                    Date firstDayOnThisMonth = TimeUtils.firstDayOnThisMonth();
                    // 分页查询参数时间范围内的系统已发布博客列表（时间范围：左闭右闭区间）
                    blogIssueService.getSynthesizeBlogList(page, sortVo, firstDayOnThisMonth, date);
                    break;
                // 博客被收藏
                case COLLECT_BLOG:
                    page.addOrder(OrderItem.desc("collect_num"));
                    // 分页查询系统已发布博客列表，根据被收藏数量降序排序
                    blogIssueService.getSynthesizeBlogList(page, sortVo);
                    break;
            }

            // 返回数据封装
            pageDto = new PageDto<>(page);
            // 缓存综合排序博客数据五分钟
            redisStringHandler.set(sortListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

            return pageDto;
        } finally {
            // 判断当前锁对象是否还持有锁 并 持有该锁的线程与当前业务线程一致
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    @Override
    public PageDto<BlogDto> hotBlogList(SortVo sortVo) {

        String hotBlogListKey = sortVo.getHotBlogListKey();
        // 查询Redis，获取热门博客列表排序缓存
        PageDto<BlogDto> pageDto = redisStringHandler.get(hotBlogListKey);
        if (pageDto != null) {
            // 尝试更新缓存键的过期时间
            redisHandler.tryUpdateKeyExpire(hotBlogListKey, 150, RandomNumUtils.random5Minutes(10));
            return pageDto;
        }
        // 获取Redis分布式锁对象
        RLock lock = redissonClient.getLock(RedisConstant.LOCK + hotBlogListKey);
        // 加锁30秒
        lock.lock(30, TimeUnit.SECONDS);

        try {
            // 重复查询Redis，获取热门博客列表排序缓存
            pageDto = redisStringHandler.get(hotBlogListKey);
            if (pageDto != null) {
                return pageDto;
            }

            // mp分页对象
            Page<BlogDto> page = new Page<>(sortVo.getPage(), sortVo.getLimit());

            // 分页查询系统热门博客列表
            blogIssueService.getHotBlogList(page, sortVo, CommonEnum.ZERO.getValue());

            // 返回数据封装
            pageDto = new PageDto<>(page);
            // 缓存热门博客列表数据五分钟
            redisStringHandler.set(hotBlogListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

            return pageDto;
        } finally {
            // 判断当前锁对象是否还持有锁 并 持有该锁的线程与当前业务线程一致
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    @Override
    public PageDto<BlogDto> getEliteBlogList(SortVo sortVo) {

        String eliteBlogListKey = sortVo.getEliteBlogListKey();
        // 获取Redis分布式锁对象
        RLock lock = redissonClient.getLock(RedisConstant.LOCK + eliteBlogListKey);
        // 查询Redis，获取热门博客列表排序缓存
        PageDto<BlogDto> pageDto = redisStringHandler.get(eliteBlogListKey);
        if (pageDto != null) {
            // 尝试更新缓存键的过期时间
            redisHandler.tryUpdateKeyExpire(lock, eliteBlogListKey, 150, RandomNumUtils.random5Minutes(10));
            return pageDto;
        }
        // 加锁30秒
        lock.lock(30, TimeUnit.SECONDS);

        try {
            // 重复查询Redis，获取热门博客列表排序缓存
            pageDto = redisStringHandler.get(eliteBlogListKey);
            if (pageDto != null) {
                return pageDto;
            }

            // mp分页对象
            Page<BlogDto> page = new Page<>(sortVo.getPage(), sortVo.getLimit());

            // 分页查询系统推荐博客列表
            blogIssueService.getEliteBlogList(page, sortVo, CommonEnum.ZERO.getValue());

            // 返回数据封装
            pageDto = new PageDto<>(page);

            // 缓存系统推荐博客列表数据五分钟
            redisStringHandler.set(eliteBlogListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

            return pageDto;
        } finally {
            // 判断当前锁对象是否还持有锁 并 持有该锁的线程与当前业务线程一致
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

}
